package emarket;

// Environment code for project EMarket

import jason.asSyntax.*;
import jason.environment.*;
import jason.stdlib.literal;

import java.util.logging.*;
import java.util.*;

public class Emarket extends Environment {

	private static final String MAINTAINER = "maintainer";
	
    private Logger logger = Logger.getLogger("EMarket."+Emarket.class.getName());
    
    
    private List<Offer> 	_offers = new ArrayList<Offer>();
    private List<Request>	_requests = new ArrayList<Request>();
    
    private Map<String, Literal>	_sendOfferPercepts = new HashMap<String, Literal>();
    
    
    

    /** Called before the MAS execution with the args informed in .mas2j */
    @Override
    public void init(String[] args) {
        super.init(args);
        addPercept(Literal.parseLiteral("percept(demo)"));
    }

    @Override
    public boolean executeAction(String agName, Structure action) {
    	
//    	logger.info("Searching for action: "+action);
    	String functor = action.getFunctor();
    	
    	if( functor.equals( "makeMatchForRequest" ) )
    	{
    		
//    		logger.info("executing: makeMatchForRequest(" + action.getTerm(0).toString() + ", "
//    				+ action.getTerm(1).toString() + ")" );
    		
    		this.makeMatchForRequest( 
    				action.getTerm(0).toString(), 
    				action.getTerm(1).toString(),
    				agName );
    		return true;
    	}
    	
    	
    	
    	if( functor.equals( "registerNewOffer" ) )
    	{
    		this.registerNewOffer(
    			action.getTerm(0).toString(),
    			action.getTerm(1).toString()
    		);
    		return true;
    	}
    	
    	
    	if( functor.equals( "makeMatchForOffer" ) )
    	{
    		this.makeMatchForOffer( 
    			action.getTerm(0).toString(),
    			action.getTerm(1).toString(),
    			agName );
    		return true;
    	}
    	
    	
    	if( functor.equals( "registerNewRequest" ) )
    	{
    		this.registerNewRequest(
				action.getTerm(0).toString(),
				action.getTerm(1).toString()
			);
    		return true;
    	}
    	
    	
    	if( functor.equals( "itemSold" ) )
    	{
    		this.itemSold(
    			action.getTerm(0).toString(),
    			action.getTerm(1).toString(),
    			action.getTerm(2).toString() 
    		);
    		return true;
    	}
    	
    	
    	if( functor.equals( "void" ) )
    		return true;
    	
    	
    	
        logger.info("executing: "+action+", but not implemented!");
        return true;
    }

    /** Called before the end of MAS execution */
    @Override
    public void stop() {
        super.stop();
    }
    

    
    
    
    // Maintainer / Matcher methods
    /** This returns a list of Traders (sellers). This is only allowed for the Maintainer agent. 
     * @param itemName The name of the item that is requested
     * @return The list of Traders (sellers).
     **/
	public List<Trader> makeMatchForRequest( String itemName, String buyer, String maintainerName ) {

		List<Trader> _tempOffers = new ArrayList<Trader>();
		
		String traderList = "newMatch(" + buyer + "," + itemName + ", [";
		
		Item newItem = new Item( itemName );
		
		for(int i=0; i<_offers.size(); i++)
		{
			if( _offers.get(i).get_item().equals( newItem ) )
			{
				if( i > 0 )
					traderList += ",";
				
				traderList += _offers.get(i).get_trader().get_identifier().toString();
			}
		}
		
		traderList += "] )";
		addPercept( maintainerName, Literal.parseLiteral( traderList ) );
		return _tempOffers;
	}
	
	
	
	
	
	public List<Trader> makeMatchForOffer( String itemName, String sellerName, String maintainerName )
	{
		
		List<Trader> _tempRequests = new ArrayList<Trader>();
		
//		String traderList = "newOfferForBuyers(" + sellerName + ", " + itemName + ", [";
		
		Item newItem = new Item( itemName );
		
		Literal lit;
		
		for( int i=0; i<_requests.size(); i++ )
		{
			if( _requests.get(i).get_item().equals( newItem ) )
			{
//				if( i > 0 )
//					traderList += ",";
				
				
				String percept = "newMatch( " + _requests.get(i).get_trader().get_identifier() + ", " + itemName + ", [" + sellerName + "] )";
				lit = Literal.parseLiteral( percept );
				
				addPercept( maintainerName, lit );
				this._sendOfferPercepts.put( itemName, lit );
				
				
				
				
//				traderList += _requests.get(i).get_trader().get_identifier().toString();
//				_tempRequests.add( _requests.get(i).get_trader() );
			}
		}
		
//		traderList += "] )";
		
//		if( _tempRequests.size() > 0 )
//		{
//			if( this._sendOfferPercepts.containsKey( itemName ) )
//			{
//				removePercept( maintainerName, this._sendOfferPercepts.get( itemName ) );
////				logger.info("makeMatchForOffer --> removePercept " + itemName );
//			}
//			
//			Literal lit = Literal.parseLiteral( traderList );
//			
//			addPercept( maintainerName,  lit );
//			this._sendOfferPercepts.put( itemName, lit );
//			
////			logger.info("makeMatchForOffer: " + traderList );
//		}		
		
		return _tempRequests;
	}
	
	
	
	/**
	 * Register a new offer in the env.
	 * @param Seller Name of the offering Trader
	 * @param itemName Name of the item
	 * @return
	 */
	public boolean registerNewOffer( String itemName, String Seller )
	{
		Offer offer = new Offer( itemName, Seller );
		
		this._offers.add( offer );
		return true;
		
	}
	
	
	/**
	 * Register a new request in the evn.
	 * @param itemName Name of the item
	 * @param Buyer Name of the requesting Trader
	 * @return
	 */
	public boolean registerNewRequest( String itemName, String Buyer )
	{
		Request request = new Request( itemName, Buyer  );
		
		this.removeRequest( Buyer, itemName);
		
		return this._requests.add( request );
	}
	
	
	/**
	 * Mark an item as sold
	 * @param itemName The name of the item sold
	 * @param Buyer The name of the requesting Agent
	 * @param Seller The name of the offering Agent
	 * @return
	 */
	public boolean itemSold( String itemName, String Buyer, String Seller  )
	{
		this.removeRequest( Buyer, itemName );
		this.removeOffer( Seller, itemName );
				
		return true;
	}
	
	
	
	/**
	 * Internal function to remove a request
	 * @param name Name of the requesting Trader
	 * @param item Name of the item
	 * @return
	 */
	private boolean removeRequest( String name, String item )
	{
		Item newItem = new Item( item );
		Trader newTrader = new Trader( name );
		
		for(int i=0; i<_requests.size(); i++)
		{
			if(_requests.get(i).get_trader().equals(newTrader)
				&& _requests.get(i).get_item().equals(newItem))
			{
				_requests.remove(i);
				return true;
			}
		}
		
		return false;
	}
	
	
	/**
	 * Internal function to remove an offer
	 * @param name Name of the offering Trader
	 * @param item Name of the item
	 * @return
	 */
	private boolean removeOffer( String name, String item )
	{
		Item newItem = new Item( item );
		Trader newTrader = new Trader( name );
		
		for(int i=0; i<_offers.size(); i++)
		{
			if(_offers.get(i).get_trader().equals(newTrader)
				&& _offers.get(i).get_item().equals(newItem))
			{
				_offers.remove(i);
				return true;
			}
		}
		
		return false;
	}
}

